﻿//
// FixPointCS
//
// Copyright(c) Jere Sanisalo, Petri Kero
// 
// Permission is hereby granted, free of charge, to any person obtaining a copy
// of this software and associated documentation files (the "Software"), to deal
// in the Software without restriction, including without limitation the rights
// to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
// copies of the Software, and to permit persons to whom the Software is
// furnished to do so, subject to the following conditions:
// 
// The above copyright notice and this permission notice shall be included in all
// copies or substantial portions of the Software.
// 
// THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
// IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
// FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
// AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
// LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
// OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
// SOFTWARE.
//
using System;
using System.Runtime.CompilerServices;
using FixedPoint;

namespace UnityEngine {

    /// <summary>
    /// Vector3 struct with signed 32.32 fixed point components.
    /// </summary>
    public struct Vector3F64 : IEquatable<Vector3F64> {
        public static Vector3F64 Zero { [MethodImpl(FixedUtil.AggressiveInlining)] get => new(Fixed64.Zero, Fixed64.Zero, Fixed64.Zero); }
        public static Vector3F64 One { [MethodImpl(FixedUtil.AggressiveInlining)] get => new(Fixed64.One, Fixed64.One, Fixed64.One); }
        public static Vector3F64 Down { [MethodImpl(FixedUtil.AggressiveInlining)] get => new(Fixed64.Zero, Fixed64.Neg1, Fixed64.Zero); }
        public static Vector3F64 Up { [MethodImpl(FixedUtil.AggressiveInlining)] get => new(Fixed64.Zero, Fixed64.One, Fixed64.Zero); }
        public static Vector3F64 Left { [MethodImpl(FixedUtil.AggressiveInlining)] get => new(Fixed64.Neg1, Fixed64.Zero, Fixed64.Zero); }
        public static Vector3F64 Right { [MethodImpl(FixedUtil.AggressiveInlining)] get => new(Fixed64.One, Fixed64.Zero, Fixed64.Zero); }
        public static Vector3F64 Forward { [MethodImpl(FixedUtil.AggressiveInlining)] get => new(Fixed64.Zero, Fixed64.Zero, Fixed64.One); }
        public static Vector3F64 Back { [MethodImpl(FixedUtil.AggressiveInlining)] get => new(Fixed64.Zero, Fixed64.Zero, Fixed64.Neg1); }
        public static Vector3F64 AxisX { [MethodImpl(FixedUtil.AggressiveInlining)] get => new(Fixed64.One, Fixed64.Zero, Fixed64.Zero); }
        public static Vector3F64 AxisY { [MethodImpl(FixedUtil.AggressiveInlining)] get => new(Fixed64.Zero, Fixed64.One, Fixed64.Zero); }
        public static Vector3F64 AxisZ { [MethodImpl(FixedUtil.AggressiveInlining)] get => new(Fixed64.Zero, Fixed64.Zero, Fixed64.One); }

        // Raw components
        public readonly long RawX => m_RawX;
        private long m_RawX;

        public readonly long RawY => m_RawY;
        private long m_RawY;

        public readonly long RawZ => m_RawZ;
        private long m_RawZ;

        public F64 X { readonly get => F64.FromRaw(m_RawX); set => m_RawX = value.Raw; }
        public F64 Y { readonly get => F64.FromRaw(m_RawY); set => m_RawY = value.Raw; }
        public F64 Z { readonly get => F64.FromRaw(m_RawZ); set => m_RawZ = value.Raw; }

        public Vector3F64(F64 x, F64 y, F64 z) {
            m_RawX = x.Raw;
            m_RawY = y.Raw;
            m_RawZ = z.Raw;
        }

        // raw ctor for internal use only
        private Vector3F64(long x, long y, long z) {
            m_RawX = x;
            m_RawY = y;
            m_RawZ = z;
        }

        public static Vector3F64 FromRaw(long rawX, long rawY, long rawZ) => new(rawX, rawY, rawZ);
        public static Vector3F64 FromRaw(int x, int y, int z) => new(Fixed64.FromInt(x), Fixed64.FromInt(y), Fixed64.FromInt(z));
        public static Vector3F64 FromRaw(float x, float y, float z) => new(Fixed64.FromFloat(x), Fixed64.FromFloat(y), Fixed64.FromFloat(z));
        public static Vector3F64 FromRaw(double x, double y, double z) => new(Fixed64.FromDouble(x), Fixed64.FromDouble(y), Fixed64.FromDouble(z));

        public static Vector3F64 operator -(Vector3F64 a) => new(-a.m_RawX, -a.m_RawY, -a.m_RawZ);
        public static Vector3F64 operator +(Vector3F64 a, Vector3F64 b) => new(a.m_RawX + b.m_RawX, a.m_RawY + b.m_RawY, a.m_RawZ + b.m_RawZ);
        public static Vector3F64 operator -(Vector3F64 a, Vector3F64 b) => new(a.m_RawX - b.m_RawX, a.m_RawY - b.m_RawY, a.m_RawZ - b.m_RawZ);
        public static Vector3F64 operator *(Vector3F64 a, Vector3F64 b) => new(Fixed64.Mul(a.m_RawX, b.m_RawX), Fixed64.Mul(a.m_RawY, b.m_RawY), Fixed64.Mul(a.m_RawZ, b.m_RawZ));
        public static Vector3F64 operator /(Vector3F64 a, Vector3F64 b) => new(Fixed64.DivPrecise(a.m_RawX, b.m_RawX), Fixed64.DivPrecise(a.m_RawY, b.m_RawY), Fixed64.DivPrecise(a.m_RawZ, b.m_RawZ));
        public static Vector3F64 operator %(Vector3F64 a, Vector3F64 b) => new(a.m_RawX % b.m_RawX, a.m_RawY % b.m_RawY, a.m_RawZ % b.m_RawZ);

        public static Vector3F64 operator +(F64 a, Vector3F64 b) => new(a.Raw + b.m_RawX, a.Raw + b.m_RawY, a.Raw + b.m_RawZ);
        public static Vector3F64 operator +(Vector3F64 a, F64 b) => new(a.m_RawX + b.Raw, a.m_RawY + b.Raw, a.m_RawZ + b.Raw);
        public static Vector3F64 operator -(F64 a, Vector3F64 b) => new(a.Raw - b.m_RawX, a.Raw - b.m_RawY, a.Raw - b.m_RawZ);
        public static Vector3F64 operator -(Vector3F64 a, F64 b) => new(a.m_RawX - b.Raw, a.m_RawY - b.Raw, a.m_RawZ - b.Raw);
        public static Vector3F64 operator *(F64 a, Vector3F64 b) => new(Fixed64.Mul(a.Raw, b.m_RawX), Fixed64.Mul(a.Raw, b.m_RawY), Fixed64.Mul(a.Raw, b.m_RawZ));
        public static Vector3F64 operator *(Vector3F64 a, F64 b) => new(Fixed64.Mul(a.m_RawX, b.Raw), Fixed64.Mul(a.m_RawY, b.Raw), Fixed64.Mul(a.m_RawZ, b.Raw));
        public static Vector3F64 operator /(F64 a, Vector3F64 b) => new(Fixed64.DivPrecise(a.Raw, b.m_RawX), Fixed64.DivPrecise(a.Raw, b.m_RawY), Fixed64.DivPrecise(a.Raw, b.m_RawZ));
        public static Vector3F64 operator /(Vector3F64 a, F64 b) => new(Fixed64.DivPrecise(a.m_RawX, b.Raw), Fixed64.DivPrecise(a.m_RawY, b.Raw), Fixed64.DivPrecise(a.m_RawZ, b.Raw));
        public static Vector3F64 operator %(F64 a, Vector3F64 b) => new(a.Raw % b.m_RawX, a.Raw % b.m_RawY, a.Raw % b.m_RawZ);
        public static Vector3F64 operator %(Vector3F64 a, F64 b) => new(a.m_RawX % b.Raw, a.m_RawY % b.Raw, a.m_RawZ % b.Raw);

        public static bool operator ==(Vector3F64 a, Vector3F64 b) => a.m_RawX == b.m_RawX && a.m_RawY == b.m_RawY && a.m_RawZ == b.m_RawZ;

        public static bool operator !=(Vector3F64 a, Vector3F64 b) => a.m_RawX != b.m_RawX || a.m_RawY != b.m_RawY || a.m_RawZ != b.m_RawZ;

        public static Vector3F64 Div(Vector3F64 a, F64 b) { long oob = Fixed64.Rcp(b.Raw); return new(Fixed64.Mul(a.m_RawX, oob), Fixed64.Mul(a.m_RawY, oob), Fixed64.Mul(a.m_RawZ, oob)); }
        public static Vector3F64 DivFast(Vector3F64 a, F64 b) { long oob = Fixed64.RcpFast(b.Raw); return new(Fixed64.Mul(a.m_RawX, oob), Fixed64.Mul(a.m_RawY, oob), Fixed64.Mul(a.m_RawZ, oob)); }
        public static Vector3F64 DivFastest(Vector3F64 a, F64 b) { long oob = Fixed64.RcpFastest(b.Raw); return new(Fixed64.Mul(a.m_RawX, oob), Fixed64.Mul(a.m_RawY, oob), Fixed64.Mul(a.m_RawZ, oob)); }
        public static Vector3F64 Div(Vector3F64 a, Vector3F64 b) => new(Fixed64.Div(a.m_RawX, b.m_RawX), Fixed64.Div(a.m_RawY, b.m_RawY), Fixed64.Div(a.m_RawZ, b.m_RawZ));
        public static Vector3F64 DivFast(Vector3F64 a, Vector3F64 b) => new(Fixed64.DivFast(a.m_RawX, b.m_RawX), Fixed64.DivFast(a.m_RawY, b.m_RawY), Fixed64.DivFast(a.m_RawZ, b.m_RawZ));
        public static Vector3F64 DivFastest(Vector3F64 a, Vector3F64 b) => new(Fixed64.DivFastest(a.m_RawX, b.m_RawX), Fixed64.DivFastest(a.m_RawY, b.m_RawY), Fixed64.DivFastest(a.m_RawZ, b.m_RawZ));
        public static Vector3F64 SqrtPrecise(Vector3F64 a) => new(Fixed64.SqrtPrecise(a.m_RawX), Fixed64.SqrtPrecise(a.m_RawY), Fixed64.SqrtPrecise(a.m_RawZ));
        public static Vector3F64 Sqrt(Vector3F64 a) => new(Fixed64.Sqrt(a.m_RawX), Fixed64.Sqrt(a.m_RawY), Fixed64.Sqrt(a.m_RawZ));
        public static Vector3F64 SqrtFast(Vector3F64 a) => new(Fixed64.SqrtFast(a.m_RawX), Fixed64.SqrtFast(a.m_RawY), Fixed64.SqrtFast(a.m_RawZ));
        public static Vector3F64 SqrtFastest(Vector3F64 a) => new(Fixed64.SqrtFastest(a.m_RawX), Fixed64.SqrtFastest(a.m_RawY), Fixed64.SqrtFastest(a.m_RawZ));
        public static Vector3F64 RSqrt(Vector3F64 a) => new(Fixed64.RSqrt(a.m_RawX), Fixed64.RSqrt(a.m_RawY), Fixed64.RSqrt(a.m_RawZ));
        public static Vector3F64 RSqrtFast(Vector3F64 a) => new(Fixed64.RSqrtFast(a.m_RawX), Fixed64.RSqrtFast(a.m_RawY), Fixed64.RSqrtFast(a.m_RawZ));
        public static Vector3F64 RSqrtFastest(Vector3F64 a) => new(Fixed64.RSqrtFastest(a.m_RawX), Fixed64.RSqrtFastest(a.m_RawY), Fixed64.RSqrtFastest(a.m_RawZ));
        public static Vector3F64 Rcp(Vector3F64 a) => new(Fixed64.Rcp(a.m_RawX), Fixed64.Rcp(a.m_RawY), Fixed64.Rcp(a.m_RawZ));
        public static Vector3F64 RcpFast(Vector3F64 a) => new(Fixed64.RcpFast(a.m_RawX), Fixed64.RcpFast(a.m_RawY), Fixed64.RcpFast(a.m_RawZ));
        public static Vector3F64 RcpFastest(Vector3F64 a) => new(Fixed64.RcpFastest(a.m_RawX), Fixed64.RcpFastest(a.m_RawY), Fixed64.RcpFastest(a.m_RawZ));
        public static Vector3F64 Exp(Vector3F64 a) => new(Fixed64.Exp(a.m_RawX), Fixed64.Exp(a.m_RawY), Fixed64.Exp(a.m_RawZ));
        public static Vector3F64 ExpFast(Vector3F64 a) => new(Fixed64.ExpFast(a.m_RawX), Fixed64.ExpFast(a.m_RawY), Fixed64.ExpFast(a.m_RawZ));
        public static Vector3F64 ExpFastest(Vector3F64 a) => new(Fixed64.ExpFastest(a.m_RawX), Fixed64.ExpFastest(a.m_RawY), Fixed64.ExpFastest(a.m_RawZ));
        public static Vector3F64 Exp2(Vector3F64 a) => new(Fixed64.Exp2(a.m_RawX), Fixed64.Exp2(a.m_RawY), Fixed64.Exp2(a.m_RawZ));
        public static Vector3F64 Exp2Fast(Vector3F64 a) => new(Fixed64.Exp2Fast(a.m_RawX), Fixed64.Exp2Fast(a.m_RawY), Fixed64.Exp2Fast(a.m_RawZ));
        public static Vector3F64 Exp2Fastest(Vector3F64 a) => new(Fixed64.Exp2Fastest(a.m_RawX), Fixed64.Exp2Fastest(a.m_RawY), Fixed64.Exp2Fastest(a.m_RawZ));
        public static Vector3F64 Log(Vector3F64 a) => new(Fixed64.Log(a.m_RawX), Fixed64.Log(a.m_RawY), Fixed64.Log(a.m_RawZ));
        public static Vector3F64 LogFast(Vector3F64 a) => new(Fixed64.LogFast(a.m_RawX), Fixed64.LogFast(a.m_RawY), Fixed64.LogFast(a.m_RawZ));
        public static Vector3F64 LogFastest(Vector3F64 a) => new(Fixed64.LogFastest(a.m_RawX), Fixed64.LogFastest(a.m_RawY), Fixed64.LogFastest(a.m_RawZ));
        public static Vector3F64 Log2(Vector3F64 a) => new(Fixed64.Log2(a.m_RawX), Fixed64.Log2(a.m_RawY), Fixed64.Log2(a.m_RawZ));
        public static Vector3F64 Log2Fast(Vector3F64 a) => new(Fixed64.Log2Fast(a.m_RawX), Fixed64.Log2Fast(a.m_RawY), Fixed64.Log2Fast(a.m_RawZ));
        public static Vector3F64 Log2Fastest(Vector3F64 a) => new(Fixed64.Log2Fastest(a.m_RawX), Fixed64.Log2Fastest(a.m_RawY), Fixed64.Log2Fastest(a.m_RawZ));
        public static Vector3F64 Sin(Vector3F64 a) => new(Fixed64.Sin(a.m_RawX), Fixed64.Sin(a.m_RawY), Fixed64.Sin(a.m_RawZ));
        public static Vector3F64 SinFast(Vector3F64 a) => new(Fixed64.SinFast(a.m_RawX), Fixed64.SinFast(a.m_RawY), Fixed64.SinFast(a.m_RawZ));
        public static Vector3F64 SinFastest(Vector3F64 a) => new(Fixed64.SinFastest(a.m_RawX), Fixed64.SinFastest(a.m_RawY), Fixed64.SinFastest(a.m_RawZ));
        public static Vector3F64 Cos(Vector3F64 a) => new(Fixed64.Cos(a.m_RawX), Fixed64.Cos(a.m_RawY), Fixed64.Cos(a.m_RawZ));
        public static Vector3F64 CosFast(Vector3F64 a) => new(Fixed64.CosFast(a.m_RawX), Fixed64.CosFast(a.m_RawY), Fixed64.CosFast(a.m_RawZ));
        public static Vector3F64 CosFastest(Vector3F64 a) => new(Fixed64.CosFastest(a.m_RawX), Fixed64.CosFastest(a.m_RawY), Fixed64.CosFastest(a.m_RawZ));

        public static Vector3F64 Pow(Vector3F64 a, F64 b) => new(Fixed64.Pow(a.m_RawX, b.Raw), Fixed64.Pow(a.m_RawY, b.Raw), Fixed64.Pow(a.m_RawZ, b.Raw));
        public static Vector3F64 PowFast(Vector3F64 a, F64 b) => new(Fixed64.PowFast(a.m_RawX, b.Raw), Fixed64.PowFast(a.m_RawY, b.Raw), Fixed64.PowFast(a.m_RawZ, b.Raw));
        public static Vector3F64 PowFastest(Vector3F64 a, F64 b) => new(Fixed64.PowFastest(a.m_RawX, b.Raw), Fixed64.PowFastest(a.m_RawY, b.Raw), Fixed64.PowFastest(a.m_RawZ, b.Raw));
        public static Vector3F64 Pow(F64 a, Vector3F64 b) => new(Fixed64.Pow(a.Raw, b.m_RawX), Fixed64.Pow(a.Raw, b.m_RawY), Fixed64.Pow(a.Raw, b.m_RawZ));
        public static Vector3F64 PowFast(F64 a, Vector3F64 b) => new(Fixed64.PowFast(a.Raw, b.m_RawX), Fixed64.PowFast(a.Raw, b.m_RawY), Fixed64.PowFast(a.Raw, b.m_RawZ));
        public static Vector3F64 PowFastest(F64 a, Vector3F64 b) => new(Fixed64.PowFastest(a.Raw, b.m_RawX), Fixed64.PowFastest(a.Raw, b.m_RawY), Fixed64.PowFastest(a.Raw, b.m_RawZ));
        public static Vector3F64 Pow(Vector3F64 a, Vector3F64 b) => new(Fixed64.Pow(a.m_RawX, b.m_RawX), Fixed64.Pow(a.m_RawY, b.m_RawY), Fixed64.Pow(a.m_RawZ, b.m_RawZ));
        public static Vector3F64 PowFast(Vector3F64 a, Vector3F64 b) => new(Fixed64.PowFast(a.m_RawX, b.m_RawX), Fixed64.PowFast(a.m_RawY, b.m_RawY), Fixed64.PowFast(a.m_RawZ, b.m_RawZ));
        public static Vector3F64 PowFastest(Vector3F64 a, Vector3F64 b) => new(Fixed64.PowFastest(a.m_RawX, b.m_RawX), Fixed64.PowFastest(a.m_RawY, b.m_RawY), Fixed64.PowFastest(a.m_RawZ, b.m_RawZ));

        public static F64 Length(Vector3F64 a) => F64.FromRaw(Fixed64.Sqrt(Fixed64.Mul(a.m_RawX, a.m_RawX) + Fixed64.Mul(a.m_RawY, a.m_RawY) + Fixed64.Mul(a.m_RawZ, a.m_RawZ)));

        public static F64 LengthFast(Vector3F64 a) => F64.FromRaw(Fixed64.SqrtFast(Fixed64.Mul(a.m_RawX, a.m_RawX) + Fixed64.Mul(a.m_RawY, a.m_RawY) + Fixed64.Mul(a.m_RawZ, a.m_RawZ)));
        public static F64 LengthFastest(Vector3F64 a) => F64.FromRaw(Fixed64.SqrtFastest(Fixed64.Mul(a.m_RawX, a.m_RawX) + Fixed64.Mul(a.m_RawY, a.m_RawY) + Fixed64.Mul(a.m_RawZ, a.m_RawZ)));
        public static F64 LengthSqr(Vector3F64 a) => F64.FromRaw(Fixed64.Mul(a.m_RawX, a.m_RawX) + Fixed64.Mul(a.m_RawY, a.m_RawY) + Fixed64.Mul(a.m_RawZ, a.m_RawZ));
        public static Vector3F64 Normalize(Vector3F64 a) { F64 ooLen = F64.FromRaw(Fixed64.RSqrt(Fixed64.Mul(a.m_RawX, a.m_RawX) + Fixed64.Mul(a.m_RawY, a.m_RawY) + Fixed64.Mul(a.m_RawZ, a.m_RawZ))); return ooLen * a; }
        public static Vector3F64 NormalizeFast(Vector3F64 a) { F64 ooLen = F64.FromRaw(Fixed64.RSqrtFast(Fixed64.Mul(a.m_RawX, a.m_RawX) + Fixed64.Mul(a.m_RawY, a.m_RawY) + Fixed64.Mul(a.m_RawZ, a.m_RawZ))); return ooLen * a; }
        public static Vector3F64 NormalizeFastest(Vector3F64 a) { F64 ooLen = F64.FromRaw(Fixed64.RSqrtFastest(Fixed64.Mul(a.m_RawX, a.m_RawX) + Fixed64.Mul(a.m_RawY, a.m_RawY) + Fixed64.Mul(a.m_RawZ, a.m_RawZ))); return ooLen * a; }

        public static F64 Dot(Vector3F64 a, Vector3F64 b) => F64.FromRaw(Fixed64.Mul(a.m_RawX, b.m_RawX) + Fixed64.Mul(a.m_RawY, b.m_RawY) + Fixed64.Mul(a.m_RawZ, b.m_RawZ));
        public static F64 Distance(Vector3F64 a, Vector3F64 b) => Length(a - b);
        public static F64 DistanceFast(Vector3F64 a, Vector3F64 b) => LengthFast(a - b);
        public static F64 DistanceFastest(Vector3F64 a, Vector3F64 b) => LengthFastest(a - b);

        public static Vector3F64 Min(Vector3F64 a, Vector3F64 b) => new(Fixed64.Min(a.m_RawX, b.m_RawX), Fixed64.Min(a.m_RawY, b.m_RawY), Fixed64.Min(a.m_RawZ, b.m_RawZ));
        public static Vector3F64 Max(Vector3F64 a, Vector3F64 b) => new(Fixed64.Max(a.m_RawX, b.m_RawX), Fixed64.Max(a.m_RawY, b.m_RawY), Fixed64.Max(a.m_RawZ, b.m_RawZ));

        public static Vector3F64 Clamp(Vector3F64 a, F64 min, F64 max) => new(Fixed64.Clamp(a.m_RawX, min.Raw, max.Raw), Fixed64.Clamp(a.m_RawY, min.Raw, max.Raw), Fixed64.Clamp(a.m_RawZ, min.Raw, max.Raw));

        public static Vector3F64 Clamp(Vector3F64 a, Vector3F64 min, Vector3F64 max) => new(Fixed64.Clamp(a.m_RawX, min.m_RawX, max.m_RawX), Fixed64.Clamp(a.m_RawY, min.m_RawY, max.m_RawY), Fixed64.Clamp(a.m_RawZ, min.m_RawZ, max.m_RawZ));

        public static Vector3F64 Lerp(Vector3F64 a, Vector3F64 b, F64 t) {
            long tb = t.Raw;
            long ta = Fixed64.One - tb;
            return new(
                Fixed64.Mul(a.m_RawX, ta) + Fixed64.Mul(b.m_RawX, tb),
                Fixed64.Mul(a.m_RawY, ta) + Fixed64.Mul(b.m_RawY, tb),
                Fixed64.Mul(a.m_RawZ, ta) + Fixed64.Mul(b.m_RawZ, tb));
        }

        public static Vector3F64 Cross(Vector3F64 a, Vector3F64 b) => new(Fixed64.Mul(a.m_RawY, b.m_RawZ) - Fixed64.Mul(a.m_RawZ, b.m_RawY), Fixed64.Mul(a.m_RawZ, b.m_RawX) - Fixed64.Mul(a.m_RawX, b.m_RawZ), Fixed64.Mul(a.m_RawX, b.m_RawY) - Fixed64.Mul(a.m_RawY, b.m_RawX));

        public readonly bool Equals(Vector3F64 other) => this == other;

        public override readonly bool Equals(object obj) {
            if (obj is not Vector3F64) {
                return false;
            }
            return ((Vector3F64)obj) == this;
        }

        public override readonly string ToString() => "(" + Fixed64.ToString(m_RawX) + ", " + Fixed64.ToString(m_RawY) + ", " + Fixed64.ToString(m_RawZ) + ")";

        public override readonly int GetHashCode() => HashCode.Combine(m_RawX, m_RawY, m_RawZ);
    }
}
